﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Package;
using SnShared.Models;
using StrongNetCliPlugin;

namespace SnClient
{
    [ComVisible(true)]
    [ComSourceInterfaces(typeof(ISnCliPluginEvents))] 
    [Guid("427A37CA-BD60-4D24-8B2F-174E52B79882")]    
    public class PackageManager : ISnCliPlugin
    {
        private Timer m_timer;
        private Boolean m_passesPolicy = false;
        private CDMRestApi m_restClient = new CDMRestApi();
        private ILogging m_logger = new Logging();

        public Boolean AutoReset { get; set; }

        public PackageManager()
        {
            AutoReset = false;
        }

        public void Init()
        {
            //System.Diagnostics.Debugger.Launch();
            ReportPackages();

            TimerCallback callback = new TimerCallback(this.CheckPackages);            
            m_timer = new Timer(callback, this, TimeSpan.Zero, TimeSpan.FromSeconds(30));
        }

        public void ReportPackages()
        {
            InstalledPackagesHelper.GetInstalledFiles(m_restClient);
        }

        public void CheckPackages(object o)
        {
            try
            {
                PackageManager pm = (PackageManager)o;
                List<SoftwarePackage> revokedPackages = m_restClient.GetRevokedPackages();
                Boolean stateChanged = false;

                pm.m_passesPolicy = true;
                
                foreach (SoftwarePackage sp in revokedPackages)
                {
                    if (pm.UninstallPackage(sp))
                        stateChanged = true;
                }
                               
                if (stateChanged)                
                    pm.SetSecurityStatus();

                pm.ReportPackages();    
            }
            catch (Exception e)
            {
                m_logger.LogException( e, LoggingEventId.EVENT_ID_EXCEPTION, "CheckPackages" );
            }
        }

        public void Shutdown()
        {
            if (m_timer != null)
                m_timer.Dispose();
        }

        public delegate void NotifyPackageRemoval(string ppwszMessage);
        public event NotifyPackageRemoval OnNotifyPackageRemoval = null;

        internal Boolean UninstallPackage(SoftwarePackage package)
        {
            try
            {


                Session s = Installer.OpenProduct(package.UniqueId);
                if (s == null)
                    return false;

                s.Close();

                
                Installer.ConfigureProduct(package.UniqueId, 0, InstallState.Absent, String.Empty);

                RemovePackage rp = new RemovePackage() { ComputerName = Environment.MachineName, Package = package};
                m_restClient.RemovePackage(rp);

                String msg2 = String.Format("Removed Package {0} ({1})", package.Name, package.UniqueId);
                m_logger.LogOneEvent(LoggingEventId.EVENT_ID_PACKAGEREMOVALSUCCESS, msg2);

                if (OnNotifyPackageRemoval != null)
                    OnNotifyPackageRemoval(msg2);

                if (AutoReset)
                {
                    Console.WriteLine("Resetting packge  {0} ({1})", package.Name, package.UniqueId);
                    m_restClient.ResetDemo(package);
                }

            }
            catch (Exception e)

            {
                String msg = String.Format("Failed to remove package {0} ({1})", package.Name, package.UniqueId);
                m_logger.LogException( e, LoggingEventId.EVENT_ID_PACKAGEREMOVALFAILURE, msg );
                m_passesPolicy = false;
            }


            return true;
        }

        //
        // Strongnet SnapIn Interfaces.
        //

        public delegate void NotifySecurityStatus(uint ulIsSecure, string ppwszMessage);
        public event NotifySecurityStatus OnNotifySecurityStatus = null;




        const string SUCCESS = "The system is free from suspect software packages.";        
        const string FAILURE = "The system has one ore more suspect software packages.  See the CDM event log for more detail.";

        void ISnCliPlugin.InitializePlugin()
        {
            Init();
        }   

        void ISnCliPlugin.GetSecurityStatus(out uint pulIsSecure, out string ppwszMessage)
        {
            pulIsSecure = Convert.ToUInt32(m_passesPolicy);
            ppwszMessage = (m_passesPolicy ? SUCCESS : FAILURE);
        }

        private void SetSecurityStatusWithMessage(string msg)
        {
            UInt32 isSecure = Convert.ToUInt32(m_passesPolicy);            

            if (this.OnNotifySecurityStatus != null)
            {
                OnNotifySecurityStatus(isSecure, msg);
            }
        }

        private void SetSecurityStatus()
        {
            UInt32 isSecure = Convert.ToUInt32(m_passesPolicy);
            String msg = (m_passesPolicy ? SUCCESS : FAILURE);            

            if (this.OnNotifySecurityStatus != null)
            {
                OnNotifySecurityStatus(isSecure, msg);
            }
        }     
    }
}
